package com.zjl.redis.第16章_分布式锁;

import com.zjl.redis.第06章_SpringBoot整合redis.B2_JedisPool;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.SetArgs;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.math.BigDecimal;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * ClassName: B_手写分布式锁
 * Package: com.zjl.redis.第16章_分布式锁
 * Description:
 *
 * @Author 张蛟龙
 * @Create 2024/7/8 18:51
 * @Version 1.0
 */
public class B2_手写分布式锁之setnx模拟1 {

    public RedisCommands<String, String> getRedisCommands() {
        //构建 配置
        RedisURI redis2 = RedisURI.builder()
                .redis("82.157.71.243", 6379)//设置 ip 端口
                .withHost("82.157.71.243")//设置 ip
                .withPort(6379)//设置  端口
                .withAuthentication("default", "er485g96er8")//设置 用户名密码
                .withPassword("er485g96er8")//设置 密码
                .build();

        //连接 reids
        RedisClient redisClient = RedisClient.create(redis2);
        StatefulRedisConnection<String, String> connect = redisClient.connect();
        //创建 操作类
        RedisCommands<String, String> sync = connect.sync();//同步的连接
        return sync;
    }

    private static String AMT = "amt";
    private static String LOCK = "LOCK";
    private static int num = 100;
    private static int fbsNum = 2;

    private static AtomicInteger atomicInteger = new AtomicInteger(0);//目的是 线程啥时候停止

    @Test
    public void 模拟归0() {
        SetArgs setParams = new SetArgs();
        setParams.nx().ex(5);
        RedisCommands<String, String> sync = getRedisCommands();
//        String xxx = sync.set(LOCK, "xxx", setParams);
//        System.out.println(sync.del(LOCK));
//        System.out.println(xxx == null);
        System.out.println("-----------");
        System.out.println(sync.get(AMT));
        sync.set(AMT, num + "");
    }

    @Test
    public void 模拟分布式加锁() throws InterruptedException {

        RedisCommands<String, String> sync = getRedisCommands();
        sync.set(AMT, num + "");//重置 数字
        for (int k = 0; k < fbsNum; k++) {//模拟 fbsNum 个分布式
            new Thread(() -> {
                try {
                    B2_手写分布式锁之setnx模拟1 b = new B2_手写分布式锁之setnx模拟1();
                    b.模拟分布式扣减库存();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();

        }
        while (atomicInteger.get() < num) {
            System.out.println(atomicInteger.get());
            TimeUnit.SECONDS.sleep(1);
        }

        Jedis redis1 = B2_JedisPool.getRedisPool();
        System.out.println("-------------模拟分布式加分布式锁模拟------------------------------");
        System.out.println(redis1.get(AMT));
        redis1.close();

    }

    private void 模拟分布式扣减库存() throws InterruptedException {
        //模拟每个java线程
        ExecutorService threadPool = new ThreadPoolExecutor(10, 10, 2L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10000));
        RedisCommands<String, String> lock = getRedisCommands();
        RedisCommands<String, String> redis = getRedisCommands();

        SetArgs setParams = new SetArgs();
        setParams.nx().ex(50);

        for (int i = 0; i < num / fbsNum; i++) {
            threadPool.execute(() -> {
                try {

                    while (lock.set(LOCK, "xxx", setParams) == null){//获取锁
                        TimeUnit.MICROSECONDS.sleep(50);
                    }

//                    atomicInteger.addAndGet(1);
                    atomicInteger.incrementAndGet();//+1

                    //模拟  分布式下的数据更新的   分布式安全
                    BigDecimal bigDecimal = new BigDecimal(redis.get(AMT));
                    BigDecimal subtract = bigDecimal.subtract(BigDecimal.valueOf(1));
                    redis.set(AMT, subtract.toString());

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.del(LOCK);//释放锁
                }
            });

        }
        threadPool.shutdown();
    }

}
